package com.gooluke.auth.filter;

import com.gooluke.auth.config.CustomUserDetailsService;
import com.gooluke.auth.util.JwtUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.lang.NonNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * JWT身份验证过滤器，用于处理每一次HTTP请求的身份验证
 * 该过滤器继承自OncePerRequestFilter，保证每个请求只被过滤一次
 */
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    // 用户详细信息服务，用于加载用户信息
    @Resource
    private CustomUserDetailsService userDetailsService;

    // JWT工具类，用于处理JWT令牌的生成、解析和验证
    @Resource
    private JwtUtils jwtUtils;

    /**
     * 核心过滤方法，处理每一个请求
     *
     * @param request     请求对象，包含HTTP请求的所有信息
     * @param response    响应对象，用于向客户端发送响应
     * @param filterChain 过滤链，用于将请求传递给下一个过滤器或目标资源
     * @throws ServletException 如果请求处理过程中发生Servlet异常
     * @throws IOException      如果请求处理过程中发生I/O异常
     */
    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
        // 解析请求中的JWT令牌
        String token = parseJwt(request);
        // 如果令牌有效，进行身份验证
        if (token != null && jwtUtils.validateToken(token)) {
            // 从令牌中获取用户名
            String userId = jwtUtils.getUsernameFromToken(token);
            // 加载用户详细信息
            UserDetails userDetails = userDetailsService.loadUserByUsername(userId);
            // 创建身份验证对象，包含用户信息和权限
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            // 设置身份验证详细信息，包括请求相关信息
            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            // 将身份验证对象存储在SecurityContext中，以供后续使用
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        // 将请求传递给下一个过滤器或目标资源
        filterChain.doFilter(request, response);
    }

    /**
     * 解析请求中的JWT令牌
     *
     * @param request 请求对象，用于获取请求头信息
     * @return 解析后的JWT令牌字符串，如果没有或格式不正确则返回null
     */
    private String parseJwt(HttpServletRequest request) {
        // 获取请求头中的Authorization字段
        String headerAuth = request.getHeader("Authorization");
        // 检查Authorization字段是否存在且以"Bearer "开头
        if (StringUtils.hasText(headerAuth) && headerAuth.startsWith("Bearer ")) {
            // 返回去掉"Bearer "前缀的令牌字符串
            return headerAuth.substring(7);
        }
        // 如果条件不满足，返回null
        return null;
    }
}
